// proxydll.cpp
#include "stdafx.h"
#include "proxydll.h"
#define Beep(x,y); 
// global variables
#pragma data_seg (".d3d9_shared")
myIDirect3DDevice9* gl_pmyIDirect3DDevice9;
myIDirect3D9*       gl_pmyIDirect3D9;
HINSTANCE           gl_hOriginalDll;
HINSTANCE           gl_hThisInstance;
#pragma data_seg ()

typedef HRESULT (WINAPI *TD3DXCreateTextureFromFileInMemory)(
  _In_   LPDIRECT3DDEVICE9 pDevice,
  _In_   LPCVOID pSrcData,
  _In_   UINT SrcDataSize,
  _Out_  LPDIRECT3DTEXTURE9 *ppTexture
);

extern TD3DXCreateTextureFromFileInMemory textfrommem;


extern UINT* aTex;

#define mmfname "WOTDebug"
#define msg  WM_USER+1339
LPVOID MapView;
HWND* target;

extern void updatetex(void* src, int size);

void DataCopy (void* p, int length)
{
	int* temp;
	temp = (int*)MapView;
	*temp = length;
	memcpy (++temp, p, length);
	SendMessageA(*target, msg, 43, 43);
}
void Log(LPCSTR s, int length)
{
	memcpy(MapView, s, length);
	SendMessageA(*target, msg, 42, 42);
	/*Beep(500, 500);
	Beep(600, 500);
	Beep(700, 500);
	Beep(800, 500);
	Beep(900, 500);*/
}
typedef int (WINAPI *TD3DPERF_BeginEvent)( D3DCOLOR col, LPCWSTR wszName );
TD3DPERF_BeginEvent OldD3DPERF_BeginEvent;

typedef int (WINAPI *TD3DPERF_EndEvent)( void );
TD3DPERF_EndEvent OldD3DPERF_EndEvent;

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	// to avoid compiler lvl4 warnings 
    LPVOID lpDummy = lpReserved;
    lpDummy = NULL;
	MapView = NULL;
	HANDLE hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0xFFFFF,  mmfname);
	if (hMap != 0)
		MapView = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
	if (MapView==NULL)
	{
		Beep(1500, 4000);
		return 0;
	}
	target = (HWND*)MapView;
	target++;
	aTex = (UINT*)target;
	*aTex=0;
	MapView = ++target;
	target--;
	target--;
    
    switch (ul_reason_for_call)
	{
	    case DLL_PROCESS_ATTACH: 
			{
			InitInstance(hModule);
			HMODULE lib = LoadLibraryA("C:\\Windows\\System32\\d3d9.dll");
			OldD3DPERF_BeginEvent = (TD3DPERF_BeginEvent) GetProcAddress(lib, "D3DPERF_BeginEvent");
			OldD3DPERF_EndEvent = (TD3DPERF_EndEvent) GetProcAddress(lib, "D3DPERF_EndEvent");
			lib = LoadLibraryA("C:\\Windows\\System32\\d3dx9_43.dll");
			textfrommem = (TD3DXCreateTextureFromFileInMemory) GetProcAddress(lib, "D3DXCreateTextureFromFileInMemory");
			}
			break;
	    case DLL_PROCESS_DETACH: ExitInstance(); break;
        
        case DLL_THREAD_ATTACH:  break;
	    case DLL_THREAD_DETACH:  break;
	}
    return TRUE;
}



int WINAPI D3DPERF_BeginEvent( D3DCOLOR col, LPCWSTR wszName )
{
	return OldD3DPERF_BeginEvent(col, wszName);
}

int WINAPI D3DPERF_EndEvent( void )
{
	return OldD3DPERF_EndEvent();
}

// Exported function (faking d3d9.dll's one-and-only export)
IDirect3D9* WINAPI Direct3DCreate9(UINT SDKVersion)
{
	if (!gl_hOriginalDll) LoadOriginalDll(); // looking for the "right d3d9.dll"
	
	// Hooking IDirect3D Object from Original Library
	typedef IDirect3D9 *(WINAPI* D3D9_Type)(UINT SDKVersion);
	D3D9_Type D3DCreate9_fn = (D3D9_Type) GetProcAddress( gl_hOriginalDll, "Direct3DCreate9");
    
    // Debug
	if (!D3DCreate9_fn) 
    {
        Log("PROXYDLL: Pointer to original D3DCreate9 function not received ERROR *", 71);
        ::ExitProcess(0); // exit the hard way
    }
	
	// Request pointer from Original Dll. 
	IDirect3D9 *pIDirect3D9_orig = D3DCreate9_fn(SDKVersion);
	
	// Create my IDirect3D8 object and store pointer to original object there.
	// note: the object will delete itself once Ref count is zero (similar to COM objects)
	gl_pmyIDirect3D9 = new myIDirect3D9(pIDirect3D9_orig);
	
	// Return pointer to hooking Object instead of "real one"
	return (gl_pmyIDirect3D9);
}

void InitInstance(HANDLE hModule) 
{
	Log("PROXYDLL: InitInstance called.", 31);
	
	// Initialisation
	gl_hOriginalDll        = NULL;
	gl_hThisInstance       = NULL;
	gl_pmyIDirect3D9       = NULL;
	gl_pmyIDirect3DDevice9 = NULL;	
	
	// Storing Instance handle into global var
	gl_hThisInstance = (HINSTANCE)  hModule;
}

void LoadOriginalDll(void)
{
    char buffer[MAX_PATH];
    
    // Getting path to system dir and to d3d8.dll
	::GetSystemDirectory(buffer,MAX_PATH);

	// Append dll name
	strcat(buffer,"\\d3d9.dll");
	
	// try to load the system's d3d9.dll, if pointer empty
	if (!gl_hOriginalDll) gl_hOriginalDll = ::LoadLibrary(buffer);

	// Debug
	if (!gl_hOriginalDll)
	{
		Log("PROXYDLL: Original d3d9.dll not loaded ERROR ****", 50);
		::ExitProcess(0); // exit the hard way
	}
}

void ExitInstance() 
{    
    Log("PROXYDLL: ExitInstance called.", 31);
	
	// Release the system's d3d9.dll
	if (gl_hOriginalDll)
	{
		::FreeLibrary(gl_hOriginalDll);
	    gl_hOriginalDll = NULL;  
	}
}